package org.uoss.applications.framework.context;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.uoss.applications.framework.configuration.AppSystemConfigurationImpl;
import org.uoss.applications.framework.configuration.IAppSystemConfiguration;
import org.uoss.core.exception.UOSSException;
import org.uoss.core.logging.ILogger;
import org.uoss.core.logging.ILoggerFactory;

public class ApplicationBeansContext {
	private static final ILogger logger = ILoggerFactory.getLogger(ApplicationBeansContext.class);
	private static ApplicationContext context = null;
	private IAppSystemConfiguration appConfigInstance;
	private String[] classPackageNames = {"com/uoss/applications/"};
	private String[] beansConfigLocations;
	private String[] actionConfigLocations;
	private String[] strutsConfigLocations;
	private PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
	
	/**
	 * Initialize XML configuration locations.
	 */
	public void initialApplicationConfig() throws UOSSException {
		if(this.classPackageNames==null||this.classPackageNames.length==0){
			throw new UOSSException("Please configure class package names.");
		}
		try{
			this.setBeansConfigLocations(this.initialBeansConfigLocations("/ctx/Biz-Application-Context.xml",true));
			this.setActionConfigLocations(this.initialBeansConfigLocations("/ctx/Web-Action-Context.xml",false));
			this.setStrutsConfigLocations(this.initialBeansConfigLocations("/ctx/Web-Struts-Context.xml",false));
		}
		catch(Exception e){
			e.printStackTrace();
			logger.error(this.getClass(), "initialApplicationConfig()", "Initialize bean context locations fail.",e);
			throw new UOSSException("Initial application config failed.",e);
		}
	}

	/**
	 * Getting spring application context.
	 * 
	 * @return
	 * @throws UOSSException
	 */
	public ApplicationContext loadBeansContext() throws UOSSException {
		if(context==null){
			try{
				this.initialApplicationConfig();
				context = new ClassPathXmlApplicationContext(this.getBeansConfigLocations(),true);
			}
			catch(Exception e){
				throw new UOSSException("Load bean context fail:",e);
			}

		}
		return context;
	}
	
	/**
	 * Define default bean context configuration file.
	 * 
	 * @return
	 * @throws UOSSException
	 */
	protected String defineDefaultDataSourceConfigLocation() {
		String contextConfigLocation = null;
		String dataSourceBizType = this.getAppConfigInstance().getSystemProperty("datasource.biztype", "false");
		String dataSourceConnType = this.getAppConfigInstance().getSystemProperty("datasource.connecttype", "jndi");
		String configFilePrefix = "false".equalsIgnoreCase(dataSourceBizType)?"":"Local-";
		if ("jdbc".equalsIgnoreCase(dataSourceConnType)) {
			contextConfigLocation = "/META-INF/" + configFilePrefix + "Application-Context-jdbc.xml";
		} 
		else if ("jndi".equalsIgnoreCase(dataSourceConnType)) {
			contextConfigLocation = "/META-INF/" + configFilePrefix + "Application-Context-jndi.xml";
		}
		return contextConfigLocation;
	}
	
	/**
	 * Getting class path of beans XML file.
	 * 
	 * @param beansConfigName
	 * @return
	 */
	private String[] initialBeansConfigLocations(String beansConfigName,boolean loadDataSource) throws UOSSException {
		Resource[] resources = null;
		List<String> configLocations = new ArrayList<String>();
		if(loadDataSource){
			Resource resource = this.resolver.getResource("classpath:" + this.defineDefaultDataSourceConfigLocation());
			if(resource==null){
				throw new UOSSException("Not found data source configuration xml.");
			}
			try {
				String reslocation = resource.getURL().getPath();
				configLocations.add(reslocation.substring(reslocation.lastIndexOf("META-INF")));
			}
			catch (IOException e) {
				e.printStackTrace();
			}
		}
		for(String packageName : this.classPackageNames){
			try {
				resources = this.resolver.getResources("classpath:" + packageName + "**" + beansConfigName);
				if(resources==null)continue;
				for(Resource res : resources){
					String reslocation = res.getURL().getPath();
					String resclasspath = reslocation.substring(reslocation.lastIndexOf(packageName));
					if(!configLocations.contains(resclasspath))
						configLocations.add(resclasspath);
				}
			}
			catch (IOException e) {
				e.printStackTrace();
			}
		}
		return configLocations.toArray(new String[configLocations.size()]);
	}

	public String[] getBeansConfigLocations() {
		return beansConfigLocations;
	}

	public void setBeansConfigLocations(String[] beansConfigLocations) {
		this.beansConfigLocations = beansConfigLocations;
	}

	public String[] getActionConfigLocations() {
		return actionConfigLocations;
	}

	public void setActionConfigLocations(String[] actionConfigLocations) {
		this.actionConfigLocations = actionConfigLocations;
	}

	public String[] getStrutsConfigLocations() {
		return strutsConfigLocations;
	}

	public void setStrutsConfigLocations(String[] strutsConfigLocations) {
		this.strutsConfigLocations = strutsConfigLocations;
	}

	public String[] getClassPackageNames() {
		return classPackageNames;
	}

	public void setClassPackageNames(String[] classPackageNames) {
		this.classPackageNames = classPackageNames;
	}

	public IAppSystemConfiguration getAppConfigInstance() {
		if(this.appConfigInstance==null){
			this.appConfigInstance = new AppSystemConfigurationImpl();
		}
		return appConfigInstance;
	}

	public void setAppConfigInstance(IAppSystemConfiguration appConfigInstance) {
		this.appConfigInstance = appConfigInstance;
	}
}
